﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Flattiverse;
using System.Threading;

namespace flattiverse
{
    public partial class GUI : Form
    {
        #region Variablen

        Vector direction = new Vector();//Vector für die Richtungsbestimmung, siehe flattiverse.move(Vector vector);
        Thread refresh; // refresh Thread
        public static bool running = true; //Thread läuft solange true
        List<Ship> meinSchiff = new List<Ship>(); // Objekt "Ship"
        int scanDegree = 0; //Scan Winkel
        int selectedShip;
        float moveDirection = (float)0.0; //Variable zur Richtungeberchnung
        float speed = -5.0f;
        Connector connector = new Connector(); //Erzeugung Connector - Instanz
        float scale = (float)4.5; //Betimmt Zoom für Radar
        List<Unit> _Units = new List<Unit>(); //Hier werde gescannte Units gesperichert
        //List<Unit> _Units2 = new List<Unit>(); //Hier werde gescannte Units gesperichert
        List<ScanInfo> scan2;
        int scanParts = 3;
        int scan2Width = 90;
        int scan2range = 800;
        float shipRadius = 50.0f, shipEnergy = 20000.0f, shipEnergyCells = 1, shipShield = 20000.0f, shipShieldCells = 1.0f;
        int shipScanSurface = 2000000;
        bool shipCloaking = false;
        //bool scan1 = false;

        #endregion Variablen

        #region log

        private void log(string message)
        {
            
            rtbLog.AppendText(message + "\n"); //Funktion zur Logdarstellung
        }
        #endregion log


        public GUI()
        {
            InitializeComponent();
            refresh = new Thread(new ThreadStart(Scan));
            
        }

        #region loginbutton
        private void button1_Click(object sender, EventArgs e)
        {
            Authentification._connector = this.connector; //Übergabe der Connectorinstanz an Klasse Authentification(verwende ich immo nicht)
            Chat._connector = this.connector;             //                                 Chat (nur verwendet zum Nachrichten senden)
            receiveMsg();   //Nachrichten empfangen
            log(Authentification.login(tbAcc.Text, tbPW.Text)); //Benutzerdaten zum login
            getAvatar();
            tChat.Start(); //timer für Chat aktualisierung starten
        }
        #endregion loginbutton

        #region disconnectbutton
        private void bDC_Click(object sender, EventArgs e)
        {
            log(Authentification.disconnect()); //disconnectet über KLasse Authentification
        }
        #endregion disconnectbutton

        #region Msg
        private void bSendMessage_Click(object sender, EventArgs e)//bei Click auf senden
        {
            Chat.sendMsg(tbMessage.Text); //Nachricht wird gesendet
            tbMessage.Text = ""; //Eingabefeld wird zurückgesetzt
        }
        private void receiveMsg()
        {
            string Msg = "Keine neuen Nachrichten";
            Flattiverse.Message _receiveMsg; //Message Klasse erstellt
            while (connector.NextMessage(out _receiveMsg)) //neue Messages werden ausgelesen
                {
                    Msg += _receiveMsg.ToString() + "\n";
                }
            rtbChat.Text = Msg; //Nachricht in Chatbox
        }
        private void refreshChat(object sender, EventArgs e)
        {
            receiveMsg(); //Funktion wird von Timer alle paar Sekunden ausgeführt
       }

        private void privateMsg(string msg) //kein Plan wie das geht :D
        {
        }
        #endregion Msg

        #region ships
        private void myShips()
        {
            log("Meine Schiffe");
            foreach (Controllable c in connector.Controllables) //liest alle meine Schiffe aus, so weit ich weiß darf man aber nur eins haben
                selectShip.Items.Add(c.Name);
        }
       
        private void bShipScan_Click(object sender, EventArgs e) //bei klikc auf Schiffe scannen
        {
            myShips(); 
        }
         private void bAddShip_Click(object sender, EventArgs e) //Klick auf Schiff hinzufügen
        {
            selectedShip = connector.Controllables.Count;
                meinSchiff.Add(new Ship(tbShipName.Text, shipRadius, shipEnergy, shipEnergyCells, shipShield, shipShieldCells, shipScanSurface, shipCloaking)); //neues Schiff
                //connector.Wait();
               // meinSchiff.Add(new Ship(tbShipName.Text));
                rtbLog.AppendText(meinSchiff[selectedShip].Radius.ToString() + "\n" + meinSchiff[selectedShip].MaxSlots.ToString() + "\n" + meinSchiff[selectedShip].EnergyCells.ToString() + "\n" + meinSchiff[selectedShip].MaxEnergy.ToString() +  "\n" + meinSchiff[selectedShip].MaxScanSurface.ToString() + "\n"  );
                connector.UniverseGroups[checkUniverses.Text].RegisterShip(meinSchiff[selectedShip]); //Registiriert Schiff in ausgewählten Universum
                //connector.Wait();
                lShip.Text = "Maximale Energie: " + meinSchiff[selectedShip].ToString() + "\n Gravitation: " + meinSchiff[selectedShip].Gravity.ToString() + " \n Slots: " + meinSchiff[selectedShip].Slots.ToString() + " / " + meinSchiff[selectedShip].MaxSlots.ToString(); //grober Schiffsüberblick
                if (!refresh.IsAlive)
                {
                    refresh.Start(); //Scan Thread wird gestartet
                    if (!tRefresh.Enabled)
                    {
                        tRefresh.Start(); //Timer für Schiffinformationenrefresh wird gestartet
                    }
                }
         }
        #endregion ships

        #region scan

         private List<Unit> scanAround() 
         {
             int buffer;
             ScanInfo addScan;
             scan2 = new List<ScanInfo>();
             for (int i = 1; i <= scanParts; i++)
             {
                 buffer = (int) moveDirection + (360 / (scanParts) * (i - 1));
                 if (buffer > 360)
                 {
                     buffer = buffer - 360;
                 }
                 addScan = new ScanInfo(buffer - scan2Width / 2, buffer + scan2Width / 2, scan2range);
                 scan2.Add(addScan);
             }
             List<Unit> Units = meinSchiff[selectedShip].Scan(scan2);
             return (Units);
         }
         private void scanUnits()
         {
             //if (scan1)
             //{
             //    List<Unit> Units = meinSchiff.Scan(scanDegree, scanRange); //Liste mit Gescannten units wird abgerufen
             //    invokeScan(Units);  //Threadübergreifend aktualisieren
             //}
             //else
             //{
                 invokeScan(scanAround());
             //}
         }
         private void invokeScan(List<Unit> Units) //funktion für Threadübergreifend aktualisieren
         {
             if (InvokeRequired)
             {
                 Invoke(new MethodInvoker(delegate() //Egal in welches element invoked wird
                 {
                     invokeScan(Units); //ruft fnkt in hauptthread invoked auf
                 }));
             }
             else
             {
                 //if (scan1)
                 //{
                 //    _Units = Units;
                 //    //variable für Hauptthread wird akutalisiert
                 //    scan1 = false;
                 //}
                 //else
                 //{
                     _Units = Units;
                     //_Units.AddRange(Units);
                     //scan1 = true;
                 //}
         }
         }
         private void Scan() //Methode wird im Thread ausgeführt
         {
             while (true)
             {
                 scanUnits(); //Units gescannt
                 if (direction != null)
                 debugScan(); // Scaninhalt wird angezeigt
                 draw(); //GUI wird gezeichnet
                 connector.Wait(); //1 sek Pause damit Scanfläche wieder verfügbar ist
             }
             

         }
    #endregion scan

        #region draw
         private void draw()
         {
             if (InvokeRequired) //in haupthread invoked
             {
                 radar.Invoke((MethodInvoker)delegate()
                 {
                     draw();
                 });
             }
             else {
                 using (Graphics drawPB = radar.CreateGraphics())
                 {
                     drawPB.PixelOffsetMode = PixelOffsetMode.Half;
                drawPB.SmoothingMode = SmoothingMode.AntiAlias;

                     drawPB.Clear(Color.Black); //hintrgrund schwarz
                     
                     foreach (Unit oneUnit in _Units) //jede Unit wird einzeln ausgelsen
                     {

                        if (oneUnit is Sun) 
                        {
                                 drawPB.FillEllipse(Brushes.LightYellow, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - ((Sun)oneUnit).CoronaRadius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - ((Sun)oneUnit).CoronaRadius / scale)), (((Sun)oneUnit).CoronaRadius / scale * 2), (((Sun)oneUnit).CoronaRadius / scale * 2));
                                 drawPB.FillEllipse(Brushes.Yellow, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                        else if (oneUnit is Planet) 
                        {
                            drawPB.FillEllipse(Brushes.SandyBrown, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                        else if (oneUnit is Moon) 
                        {
                            drawPB.FillEllipse(Brushes.DimGray, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                        else if (oneUnit is BlackHole)
                        {
                            drawPB.FillEllipse(Brushes.DarkViolet, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                        else if (oneUnit is Meteoroid)
                        {
                            drawPB.FillEllipse(Brushes.Brown, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                         else if (oneUnit is Explosion)
                        {
                             drawPB.FillEllipse(Brushes.Red, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                         }
                        else if (oneUnit is PlayerShip)
                        {
                                 drawPB.FillEllipse(Brushes.GreenYellow, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                        else if (oneUnit is AIShip)
                        {
                                  drawPB.FillEllipse(Brushes.OrangeRed, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                             else if (oneUnit is Shot) 
                        {
                                 drawPB.FillEllipse(Brushes.LightGreen, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                              else if (oneUnit is MissionTarget) 
                        {
                                  drawPB.FillEllipse(Brushes.White, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                        }
                        else if (oneUnit is Buoy)
                        {
                            Buoy buffer = (Buoy)oneUnit;
                            drawPB.FillEllipse(Brushes.White, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                            drawPB.DrawString(buffer.Message + " : " + oneUnit.Gravity, new Font("Verdana", 9.0f), Brushes.Magenta, ((float)radar.Width / 2.0f + oneUnit.Position.X / scale + +12), ((float)radar.Height / 2.0f + oneUnit.Position.Y / scale + 12));
                        
                        }
                             else 
                        {
                                  drawPB.FillEllipse(Brushes.Magenta, ((float)radar.Width / 2.0f + (oneUnit.Position.X / scale - oneUnit.Radius / scale)), ((float)radar.Height / 2.0f + (oneUnit.Position.Y / scale - oneUnit.Radius / scale)), (oneUnit.Radius / scale * 2), (oneUnit.Radius / scale * 2));
                         }
                         //beschrifte Unit in ihrem Mittelpunkt
                         drawPB.DrawString(oneUnit.Name + " : " + oneUnit.Gravity, new Font("Verdana", 9.0f), Brushes.Magenta,((float)radar.Width / 2.0f + oneUnit.Position.X / scale),((float)radar.Height / 2.0f + oneUnit.Position.Y / scale));

                     }
                     drawPB.FillEllipse(Brushes.DarkCyan, (radar.Width / 2.0f), (radar.Height / 2.0f), (meinSchiff[selectedShip].Radius / scale * 2), (meinSchiff[selectedShip].Radius / scale * 2)); //zeichne mich in der mitte

                 }

             }
         }

        #endregion draw

        #region move

         private void move(object sender, MouseEventArgs e) 
         {
             if (e.Button == MouseButtons.Left) //linker mausclick
             {
                 
                 Vector buffer = new Vector(e.X - radar.Width / 2, e.Y - radar.Height / 2); //Buffervector von muaskoordinaten
                 moveDirection = (float)buffer.Angle; //Winkel des Vectors berchnet 
                 direction.Angle = (float)moveDirection;
                 direction.Length = (float)meinSchiff[selectedShip].MaxMoveLength - speed; //Bewegunsvector wird erstellt
                 lDebugMove.Text = moveDirection.ToString() ;
                 meinSchiff[selectedShip].Move(direction); //Bewegungsimpuls wird ausgeführt
                 scanDegree = (int)moveDirection; //Scanwinkel wird aktualisiert
                 rtbDebug.Text = Convert.ToString(buffer); //zum debuggen wird buffervector angezeigt
             }
             else if (e.Button == MouseButtons.Right)
             {
                 direction.Angle += 180;
                 if (direction.Angle > 360)
                 {
                     direction.Angle -= 360;
                 }
                 meinSchiff[selectedShip].Move(direction);
             }
         }
        
         #endregion move

        #region debug
         private void debugScan() //Funktion für Unitanzeige als Text, wieder in Haupthread invoked
         {
             if (InvokeRequired)
             {
                 rtbDebug.Invoke((MethodInvoker)delegate()
                 {
                     debugScan();
                 });
             }
             else
             {
                 rtbDebug.Text = "";
                 foreach (Unit oneUnit in _Units)
                 {
                     
                     rtbDebug.Text += oneUnit.ToString() + " : " + oneUnit.Position.ToString() + ", " + oneUnit.Radius.ToString() + ", " + oneUnit.Fixed + "\n"; 
                     if (oneUnit is Sun)
                     {
                         rtbDebug.Text += "\n" + ((Sun)oneUnit).CoronaRadius.ToString();
                     }
                 }
                 rtbDebug.Text += meinSchiff[selectedShip].Radius.ToString();
             }
         }
         private void GUI_FormClosed(object sender, FormClosedEventArgs e)
         {
             if (refresh.IsAlive)
                 refresh.Abort();
             //if (pCon != null)
             //{   
             //    unregisterAllShips();
             //    pCon.Disconnect();
             //}

             tChat.Stop();
             tRefresh.Stop();
         }
        #endregion debug

         private void refreshInfos(object sender, EventArgs e) //timer refresht Schiffinfos
         {
             lShip.Text = "Schiffinformationen: \n Energie: " + meinSchiff[selectedShip].Energy + "\n MxMvLngth: " + meinSchiff[selectedShip].MaxMoveLength + "\n Shield: " + meinSchiff[selectedShip].Shields;
         }

        #region Avatar
         private void bBrowse_Click(object sender, EventArgs e)
         {
             tbPath.ReadOnly = false;
             OpenFileDialog fileDlg = new OpenFileDialog();
             fileDlg.ShowDialog();
             if (fileDlg.CheckPathExists)
             {
                 tbPath.Text = fileDlg.FileName;
                 tbPath.ReadOnly = true;
                 tbPath.BackColor = Color.White;
             }
         }

         private void bUpload_Click(object sender, EventArgs e)
         {
             connector.Account.Avatar = new Bitmap(tbPath.Text);
         }
         private void getAvatar()
         {
             if (connector.Account.Avatar != null)
             {
                 using (Graphics drawPB = pbAvatar.CreateGraphics())
                 {
                     drawPB.DrawImage(new Bitmap(connector.Account.Avatar), 0.0f, 0.0f,pbAvatar.Width, pbAvatar.Height);
                 }
             }
         }

         #endregion Avatar

         private void bSelectShip_Click(object sender, EventArgs e)
         {
             selectedShip = selectShip.SelectedIndex;
         }
    }
}
